/****************************************************************************
  ECE 486 Project 1
  PDP-8 Simulator

  io.cpp

  Input/Output instructions
****************************************************************************/

#include <iostream>
#include <fstream>
#include "stdafx.h"
#include "winmain.h"
#include "header.h"

// Global variables for io.cpp
char keybuf[81];			//one line buffer existing on Keyboard's end
int keybufindex = 0;
int keybufsize = 0;
const int keybufsizemax = 80;


// Decode and Exectue IO instructions
int IO( unsigned short inst, HWND hDlg )
{
	unsigned short device = inst & 00770;		
	device >>= 3;								// Device ID of the IO instruction
	unsigned short op = inst &00007;			// Operation type of the instruction
	unsigned short character = KF_KB & 000377;	// character contained in low order 8bit
												// of KF_KB

	if(device == 003)	//Keyboard Input instruction
	{
		switch (op)
		{
		case 0:
			//KCF - Keyboard Clear Flags (PDP-8/E)
			KF_KB &= 007777;
			break;
		case 1:
			//KSF - Keyboard Skip if Flag (ALL)
			//(If KF=1 (input data ready), skip next instruction)
			if(KF_KB & 010000) ++PC;
			break;
		case 2:
			//KCC - Keyboard Clear and read character clear (ALL)
			//clear KF + clear AC + initialize reading
			LB_AC &= 010000;
			KF_KB &= 007777;
			break;
		case 4:
			//KRS - Keyboard Read Static (ALL)
			//OR KF_KB[4:11] with AC
			LB_AC |= character;
			updateKeybuf(hDlg);
			updatedisplay(hDlg);
			updateIDC_KB(hDlg);
			break;
		case 5:
			//KIE - Keyboard Interrupt Enable (PDP-8/E) 
			//Load AC to DCR  (interrupt enable and status eanble bits)
			break;
		case 6:
			//KRB - Keyboard Read and begin next read 
			//Load KF_KB[4:11] to AC + Clear KF (KCC -> KRS)
			LB_AC &= 010000;
			LB_AC |= character;
			KF_KB &= 017777;
			updatedisplay(hDlg);
			updateKeybuf(hDlg);
			updateIDC_KB(hDlg);
			break;
		default:;
		}
	}
	else if(device == 004)	//PrinterInput
	{
		switch (op)
		{
		case 0:
			//TFL Teleprinter Flag set (PDP-8/E)
			//Set TF (output data ready)
			TF_TB |= 010000;
			break;
		case 1:
			//TSF  TSF Teleprinter Skip if Flag. TF
			//If TF set, skip next instruction (ALL)
			if(TF_TB & 010000) ++PC;
			break;
		case 2:
			//TCF Teleprinter Clear Flag (ALL)
			//Clear TF
			TF_TB &= 007777;
			break;
		case 4:
			//TPC Teleprinter Print (ALL)
			//AC[4:11] -> TB
			TF_TB &= 010000;
			character = LB_AC & 000377;
			TF_TB |= character;
			updateIDC_TB(hDlg);
			outputIDC_TB(hDlg);
			updateIDC_TB(hDlg);
			break;
		case 5:
			//TSK Teleprinter Skip (PDP-8/E)
			//If KF or TF set, skip next instruction
			if((TF_TB & 010000) || (KF_KB & 010000)) ++PC;
			break;
		case 6:
			//TLS Teleprinter Load and start (ALL) 
			//AC[4:11] -> TB , Initiate output, Clear TF (TCF+TPC)
			TF_TB &= 010000;
			character = LB_AC & 000377;
			TF_TB |= character;
			TF_TB &= 007777;
			updateIDC_TB(hDlg);
			outputIDC_TB(hDlg);
			updateIDC_TB(hDlg);
			break;
		default:;
		}
	}

	return 0;
}

// Read user input
int readline(HWND hwnd)
{
	int linelen = GetWindowTextLength(GetDlgItem(hwnd, IDC_TYPE));

	if(!(KF_KB & 010000) && linelen)	// Accept input only when KF cleared and input length > 0
	{
		char* buf = new char[linelen];
		
		keybufindex = 0;
		keybufsize = linelen;

		GetDlgItemText(hwnd, IDC_TYPE, buf, keybufsizemax);

		HWND hEdit = GetDlgItem (hwnd, IDC_DISP);
		int ndx = GetWindowTextLength (hEdit);

		strcpy_s(keybuf,keybufsizemax, buf);

		strcat_s(buf,linelen+2, "\n");
		
		SendMessage (hEdit, EM_SETSEL, (WPARAM)ndx, (LPARAM)ndx);
		SendMessage (hEdit, EM_REPLACESEL, ndx, (LPARAM) buf);


		KF_KB |= 010000;

		unsigned short character = keybuf[keybufindex];
		character &= 000377;
		character |= 000200;
		KF_KB |= character;
		updateIDC_KB(hwnd);

		buf = NULL;
	}
	else;

	return 0;
}

// Update keyboard buffer state
int updateKeybuf(HWND hwnd)
{
	if(keybufsize > keybufindex)
	{
		unsigned short character = keybuf[++keybufindex];
		character &= 000377;
		character |= 000200;
		KF_KB &= 010000;
		KF_KB |= character;

		updateIDC_KB(hwnd);
	}
	else
		KF_KB &= 007777;

	if(keybufindex == keybufsize)
		KF_KB &= 007577;


	return 0;
}

// Update KB display
void updateIDC_KB(HWND hDlg)
{
	char *outbuf = new char[10];

	sprintf_s(outbuf,9,"%05o", KF_KB);

	SetDlgItemText(hDlg, IDC_KB, outbuf);

	sprintf_s(outbuf,9,"%c", KF_KB & 000177);
	SetDlgItemText(hDlg, IDC_KC, outbuf);
	
	return;
}

// Update PB display
void updateIDC_TB(HWND hDlg)
{
	char *outbuf = new char[10];

	sprintf_s(outbuf,9,"%05o", TF_TB);

	SetDlgItemText(hDlg, IDC_TB, outbuf);

	sprintf_s(outbuf,9,"%c", TF_TB & 000177);
	SetDlgItemText(hDlg, IDC_TC, outbuf);
	

	return;
}

// Update the text edit control with contents of TB
void outputIDC_TB(HWND hDlg)
{
	if(TF_TB & 007777)
	{
		HWND hEdit = GetDlgItem (hDlg, IDC_DISP);
		int ndx = GetWindowTextLength (hEdit);
		char *outbuf = new char[10];

		sprintf_s(outbuf,9,"%c", TF_TB & 000177);
		//if(keybufindex == keybufsize)
		//	sprintf_s(outbuf,10,"%c\n",TF_TB & 000177);
		
		SendMessage (hEdit, EM_SETSEL, (WPARAM)ndx, (LPARAM)ndx);
		SendMessage (hEdit, EM_REPLACESEL, ndx, (LPARAM) outbuf);

		TF_TB &= 007777;
		TF_TB |= 010000; //TB ready;
	}

	return;
}

int IO(unsigned short inst)
{
	return 0;
}